#Covered by GPL V2.0
#Coded by Carlos del Ojo Elias (deepbit@gmail.com)


import cherrypy
import os
from base64 import b64decode
from wfDomain import *
from urlparse import urlparse,urlunparse
import webbrowser
import time
import sys
from version import *


class webGUI:

	def __init__(self):
		self.filedicts=self.getDiccFiles2("wordlists")
		self.domain=wfDomain()
		self.fuzzActive=-1
		cherrypy.config.update({'error_page.404': self.error_page_404})
		self.proxyUrl=""

		self.information=[]

		try:
			a=Request()
			a.setUrl("http://webreak.googlecode.com/svn/trunk/version.py")
			a.setTotalTimeout(2)
			a.perform()
			newver=a.response.getContent().split('"')[1]

			if (newver!=WBVERSION and "WBVERSION" in a.response.getContent()):
				inf=[ "Version [%s] is available! Upgrade in <a href=\"http://code.google.com/p/webreak/\">http://code.google.com/p/webreak/</a>" % (newver), 7] 
				self.information.append(str(inf).replace('"','\\"').replace("'",'"'))
		except:
			pass

		time.sleep(2)
		webbrowser.open("http://localhost:8007/")

	def error_page_404(self,status=None,message=None,traceback=None,version=None):
		a,b,c,_,_,_=urlparse(self.proxyUrl)
		_,_,cc,d,e,_=urlparse(cherrypy.request.path_info)

		url=urlunparse((a,b,cc,d,e,''))
		req=Request()
		req.setUrl(url)
		req.head()
		if req.response.code!=200:
			url=urlunparse((a,b,(c+cc).replace('//','/'),d,e,''))

		cherrypy.response.status=302
		cherrypy.response.headers['Location']= url
		return ""

	def logout(self,_dc=0):
		sys.exit(0)
		return ""
	logout.exposed=True

	def CancelFuzz(self,id,_dc=0):
		self.domain.cancelFuzz(int(id))
		return "{ success: true }"
	CancelFuzz.exposed=True

	def DeleteFuzz(self,id,_dc=0):
		self.domain.deleteFuzz(int(id))
		return "{ success: true }"
	DeleteFuzz.exposed=True

	def index(self,_dc=0):
		self.fuzzActive=-1
		a=file(os.path.join(cur_dir,"webfiles","index.html"))
		res="".join(a.readlines())
		cherrypy.response.headers['Expires']= "-1"
		return res
	index.exposed = True

	def getStatus(self,_dc=0):
		newList=self.domain.getinfoFuzz()

		cherrypy.response.headers['Content-Type'] = "text/javascript; charset=UTF-8"
		cherrypy.response.headers['X-Content-Type-Options']= "nosniff"
		cherrypy.response.headers['Expires']= "-1"
		status="status: "+str(newList).replace("'",'"').replace("\\\"",'"')
		res=self.domain.updateResults(self.fuzzActive)
		results=", results: "+str(res).replace("'",'"').replace("\\\"",'"')
		info=""
		if self.information:
			info=",info: ["+",".join(self.information)+"]"
			self.information=[]

		return "{ success: true , msg: { "+status+results+info+" }  }"
	getStatus.exposed=True

	def getAllResults(self,_dc=0):
		res=self.domain.getAllResults(self.fuzzActive)
		return "\r\n"+str(res).replace("'",'"').replace("\\\"",'"')+"\r\n"
	getAllResults.exposed=True

	def getResult(self,nres,_dc=0):
		res,data=self.domain.getResult(self.fuzzActive,int(nres))
		self.proxyUrl=data[0]
		cherrypy.response.headers["Content-Type"]=data[2]
		return res
	getResult.exposed=True

	def selectFuzz(self,nfuzz,_dc=0):
		self.fuzzActive=int(nfuzz)
		return "{ sucess: true, msg: %s }" % (self.getAllResults())
	selectFuzz.exposed=True

	def getDiccFiles(self,_dc=0):
		return str([[i] for i in self.getDiccFiles2("wordlists")])
	getDiccFiles.exposed=True
		
	def getEncodings(self,_dc=0):
		return str([[i] for i in self.domain.getEncodings()])
	getEncodings.exposed=True

	def getDiccFiles2(self,path):
		all=os.listdir(path)
		dirs=[os.path.join(path,i) for i in all if os.path.isdir(os.path.join(path,i))]
		files=[os.path.join(path,i) for i in all if os.path.isfile(os.path.join(path,i)) and i.split(".")[-1].lower()=="txt"]

		for i in dirs:
			files+=self.getDiccFiles2(i)

		return files

	def launchFuzz2(self,ck,headers,proxy,threads,authtype,auth,urls,recursion,extensions,dic,_dc=0):
		cherrypy.response.headers['Content-Type'] = "text/javascript; charset=UTF-8"
		cherrypy.response.headers['X-Content-Type-Options']= "nosniff"
		cherrypy.response.headers['Expires']= "-1"
		ck=b64decode(ck)
		proxy=b64decode(proxy)
		try:
			threads=int(b64decode(threads))
		except:
			return "{ success: false, msg: 'Threads must be a number' }"
		authtype=b64decode(authtype).lower()
		if authtype not in ["none","ntlm","basic","digest"]:
			return "{ success: false, msg: 'Auth type: invalid authtype' }"
		auth=b64decode(auth)
		if authtype!="none" and len(auth.split(":"))!=2:
			return "{ success: false, msg: 'invalid auth String: user:pass' }"

		urls=b64decode(urls)
		recursion=b64decode(recursion)
		extensions=b64decode(extensions)
		dic=b64decode(dic)

		headers=b64decode(headers).split("\n")
		headstrat={}
		for i in headers:
			i=i.strip()

			if ":" in i:
				try:
					k,v=i.split(":")
					k=k.strip()
					v=v.strip()
					if not k or not v:
						raise Exception
					headstrat[k]=v
				except:
					return "{ success: false, msg: 'Invalid header: %s' }" % (i.replace("<","&lt;"))
		
		try:
			if dic not in self.filedicts:
				raise Exception
		except:
			return "{ success: false, msg: 'Invalid payload: %s' }" % (i.replace("<","&lt;"))

		try:
			cnt=self.domain.addPathFuzz(ck,headstrat,proxy,threads,authtype,auth,urls,recursion,extensions,dic)
		except Exception,a:
			return str(a)

		return "{ success: true, msg: '%d  Fuzzings launched!' }" % (cnt)
	launchFuzz2.exposed = True	


	def launchFuzz(self,ck,headers,proxy,threads,authtype,auth,url,post,payloads,_dc=0):
		cherrypy.response.headers['Content-Type'] = "text/javascript; charset=UTF-8"
		cherrypy.response.headers['X-Content-Type-Options']= "nosniff"
		cherrypy.response.headers['Expires']= "-1"

		ck=b64decode(ck)
		proxy=b64decode(proxy)
		try:
			threads=int(b64decode(threads))
		except:
			return "{ success: false, msg: 'Threads must be a number' }"
		authtype=b64decode(authtype).lower()
		if authtype not in ["none","ntlm","basic","digest"]:
			return "{ success: false, msg: 'Auth type: invalid authtype' }"
		auth=b64decode(auth)
		if authtype!="none" and len(auth.split(":"))!=2:
			return "{ success: false, msg: 'invalid auth String: user:pass' }"
		url=b64decode(url)
		post=b64decode(post)

		headers=b64decode(headers).split("\n")
		headstrat={}
		for i in headers:
			i=i.strip()

			if ":" in i:
				try:
					k,v=i.split(":")
					k=k.strip()
					v=v.strip()
					if not k or not v:
						raise Exception
					headstrat[k]=v
				except:
					return "{ sucess: false, msg: 'Invalid header: %s ' }" % (i.replace("<","&lt;"))
		


		payloads=b64decode(payloads).split("|")
		paytrat=[]
		for i in payloads:
			if i:
				j=i.split(",")
				paytrat.append(j)
				try:
					j[1]=j[1].lower()
					if not j[0] or j[1] not in ["file","range","hexrange"]:
						raise Exception
					if j[1]=="file" and j[2] not in self.filedicts:
						raise Exception
				except:
					return "{ success: false , msg: 'Invalid payload: %s' }" % (i.replace("<","&lt;"))

		try:
			self.domain.addGeneralFuzz(ck,headstrat,proxy,threads,authtype,auth,url,post,paytrat)
		except Exception,a:
			return "{ success: false, msg: 'Launch failed: %s' }" % (str(a))

		return "{ success: true, msg: 'Fuzz launched!' }"
	launchFuzz.exposed = True	
		

cur_dir=current_dir = os.path.dirname(os.path.abspath(__file__))
conf = {'/webreak.css': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(cur_dir, 'webfiles','webreak.css')} ,
		'/ext': {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(cur_dir,'webfiles', 'ext')} ,
		'/images': {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(cur_dir,'webfiles', 'images')} ,
		'/encodings.js': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(cur_dir, 'webfiles','encodings.js')} ,
		'/ext.js': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(cur_dir, 'webfiles','ext.js')} ,
		'/extras.js': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(cur_dir, 'webfiles','extras.js')} ,
		'/main.js': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(cur_dir, 'webfiles','main.js')} ,
		'global':{'server.socket_host':'0.0.0.0', 'log.screen': False, 'server.socket_port' : 8007}
}

def createDaemon():
	"""Detach a process from the controlling terminal and run it in the
	background as a daemon.
	"""

	try:
	  pid = os.fork()
	except OSError, e:
	  raise Exception, "%s [%d]" % (e.strerror, e.errno)

	if (pid == 0):	# The first child.
	  os.setsid()

	  try:
		 pid = os.fork()	# Fork a second child.
	  except OSError, e:
		 raise Exception, "%s [%d]" % (e.strerror, e.errno)


	  if pid:
		 os._exit(0)	# Exit parent (the first child) of the second child.
	else:
	  os._exit(0)	# Exit parent of the first child.

	os.open(os.devnull, os.O_RDWR)	# standard input (0)

	os.dup2(0, 1)			# standard output (1)
	os.dup2(0, 2)			# standard error (2)

	try:
		cherrypy.quickstart(webGUI(),config=conf)
	except IOError,a:
		sys.exit(0)

if sys.argv[-1]=="run":
	cherrypy.quickstart(webGUI(),config=conf)   
else:
		if os.name=="posix":
			createDaemon()
		elif os.name=="nt":
			os.system("start /b python "+sys.argv[0]+" run")
		else:
			print "Unknown OS"
			raw_input()
	
